/**
 * 文件对象存储工具
 * 用于文件上传和管理
 */

/**
 * 文件上传配置
 */
const uploadConfig = {
  // 最大文件大小（字节）
  maxSize: 10 * 1024 * 1024, // 10MB
  // 允许的文件类型
  allowedTypes: [
    'image/jpeg',
    'image/jpg',
    'image/png',
    'image/gif',
    'image/bmp',
    'image/webp',
    'application/pdf',
    'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'application/vnd.ms-excel',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'application/vnd.ms-powerpoint',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation',
    'text/plain',
    'video/mp4',
    'video/avi',
    'video/quicktime',
    'audio/mpeg',
    'audio/wav',
    'application/zip',
    'application/x-rar-compressed'
  ],
  // 图片压缩配置
  imageCompress: {
    quality: 0.8,
    maxWidth: 1920,
    maxHeight: 1080
  }
}

/**
 * 文件验证
 * @param {File} file - 文件对象
 * @returns {object} 验证结果
 */
export const validateFile = (file) => {
  const result = {
    valid: true,
    message: ''
  }

  // 检查文件大小
  if (file.size > uploadConfig.maxSize) {
    result.valid = false
    result.message = `文件大小不能超过 ${formatFileSize(uploadConfig.maxSize)}`
    return result
  }

  // 检查文件类型
  if (!uploadConfig.allowedTypes.includes(file.type)) {
    result.valid = false
    result.message = '不支持的文件类型'
    return result
  }

  return result
}

/**
 * 格式化文件大小
 * @param {number} size - 文件大小（字节）
 * @returns {string} 格式化后的文件大小
 */
export const formatFileSize = (size) => {
  if (size === 0) return '0 B'
  
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(size) / Math.log(k))
  
  return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

/**
 * 获取文件扩展名
 * @param {string} filename - 文件名
 * @returns {string} 文件扩展名
 */
export const getFileExtension = (filename) => {
  return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2).toLowerCase()
}

/**
 * 获取文件类型
 * @param {string} filename - 文件名
 * @returns {string} 文件类型
 */
export const getFileType = (filename) => {
  const ext = getFileExtension(filename)
  
  const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']
  const documentExts = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']
  const videoExts = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv']
  const audioExts = ['mp3', 'wav', 'flac', 'aac', 'ogg']
  const archiveExts = ['zip', 'rar', '7z', 'tar', 'gz']
  
  if (imageExts.includes(ext)) return 'image'
  if (documentExts.includes(ext)) return 'document'
  if (videoExts.includes(ext)) return 'video'
  if (audioExts.includes(ext)) return 'audio'
  if (archiveExts.includes(ext)) return 'archive'
  
  return 'unknown'
}

/**
 * 压缩图片
 * @param {File} file - 图片文件
 * @param {object} options - 压缩选项
 * @returns {Promise<File>} 压缩后的文件
 */
export const compressImage = (file, options = {}) => {
  return new Promise((resolve, reject) => {
    const { quality = 0.8, maxWidth = 1920, maxHeight = 1080 } = {
      ...uploadConfig.imageCompress,
      ...options
    }

    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    const img = new Image()

    img.onload = () => {
      // 计算压缩后的尺寸
      let { width, height } = img
      
      if (width > maxWidth || height > maxHeight) {
        const ratio = Math.min(maxWidth / width, maxHeight / height)
        width *= ratio
        height *= ratio
      }

      canvas.width = width
      canvas.height = height

      // 绘制压缩后的图片
      ctx.drawImage(img, 0, 0, width, height)

      // 转换为Blob
      canvas.toBlob(
        (blob) => {
          if (blob) {
            const compressedFile = new File([blob], file.name, {
              type: file.type,
              lastModified: Date.now()
            })
            resolve(compressedFile)
          } else {
            reject(new Error('图片压缩失败'))
          }
        },
        file.type,
        quality
      )
    }

    img.onerror = () => {
      reject(new Error('图片加载失败'))
    }

    img.src = URL.createObjectURL(file)
  })
}

/**
 * 读取文件内容
 * @param {File} file - 文件对象
 * @param {string} readAs - 读取方式：'text', 'dataURL', 'arrayBuffer', 'binaryString'
 * @returns {Promise} 文件内容
 */
export const readFile = (file, readAs = 'dataURL') => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()

    reader.onload = (e) => {
      resolve(e.target.result)
    }

    reader.onerror = () => {
      reject(new Error('文件读取失败'))
    }

    switch (readAs) {
      case 'text':
        reader.readAsText(file)
        break
      case 'dataURL':
        reader.readAsDataURL(file)
        break
      case 'arrayBuffer':
        reader.readAsArrayBuffer(file)
        break
      case 'binaryString':
        reader.readAsBinaryString(file)
        break
      default:
        reader.readAsDataURL(file)
    }
  })
}

/**
 * 下载文件
 * @param {string} url - 文件URL
 * @param {string} filename - 文件名
 */
export const downloadFile = (url, filename) => {
  const link = document.createElement('a')
  link.href = url
  link.download = filename
  link.style.display = 'none'
  
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}

/**
 * 下载Blob文件
 * @param {Blob} blob - Blob对象
 * @param {string} filename - 文件名
 */
export const downloadBlob = (blob, filename) => {
  const url = URL.createObjectURL(blob)
  downloadFile(url, filename)
  URL.revokeObjectURL(url)
}

/**
 * 预览文件
 * @param {File} file - 文件对象
 * @returns {Promise<string>} 预览URL
 */
export const previewFile = (file) => {
  return new Promise((resolve, reject) => {
    const fileType = getFileType(file.name)
    
    if (fileType === 'image') {
      readFile(file, 'dataURL').then(resolve).catch(reject)
    } else {
      reject(new Error('不支持预览的文件类型'))
    }
  })
}

/**
 * 文件上传类
 */
export class FileUploader {
  constructor(options = {}) {
    this.options = {
      url: '/api/upload',
      method: 'POST',
      headers: {},
      data: {},
      onProgress: null,
      onSuccess: null,
      onError: null,
      ...options
    }
  }

  /**
   * 上传单个文件
   * @param {File} file - 文件对象
   * @returns {Promise} 上传结果
   */
  upload(file) {
    return new Promise((resolve, reject) => {
      // 验证文件
      const validation = validateFile(file)
      if (!validation.valid) {
        reject(new Error(validation.message))
        return
      }

      // 模拟上传成功
      setTimeout(() => {
        const mockResult = {
          success: true,
          data: {
            url: URL.createObjectURL(file),
            filename: file.name,
            size: file.size,
            type: file.type,
            uploadTime: new Date().toISOString()
          },
          message: '上传成功'
        }

        if (this.options.onSuccess) {
          this.options.onSuccess(mockResult)
        }

        resolve(mockResult)
      }, 1000)

      // 模拟上传进度
      if (this.options.onProgress) {
        let progress = 0
        const timer = setInterval(() => {
          progress += 10
          this.options.onProgress({ percent: progress })
          
          if (progress >= 100) {
            clearInterval(timer)
          }
        }, 100)
      }
    })
  }

  /**
   * 批量上传文件
   * @param {Array<File>} files - 文件数组
   * @returns {Promise} 上传结果
   */
  uploadMultiple(files) {
    const uploadPromises = files.map(file => this.upload(file))
    return Promise.all(uploadPromises)
  }
}

/**
 * 创建文件上传器
 * @param {object} options - 配置选项
 * @returns {FileUploader} 文件上传器实例
 */
export const createUploader = (options = {}) => {
  return new FileUploader(options)
}

export default {
  validateFile,
  formatFileSize,
  getFileExtension,
  getFileType,
  compressImage,
  readFile,
  downloadFile,
  downloadBlob,
  previewFile,
  FileUploader,
  createUploader
}